﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;

namespace Red.Launcher.ViewModels.Workspaces.Database.Sql
{
    public class Insert : Query
    {
        #region Private Consts

        private const string _getOutputIdSqlTemplate = @"(SELECT id FROM
                                                        ( SELECT ROW_NUMBER() OVER (ORDER BY id ASC) AS rownumber, id FROM @output_{0} ) AS foo
                                                        WHERE rownumber = {1})
                                                        ";

        #endregion Private Consts

        #region Private Data

        private int _insertIndex = -1;

        #endregion Private Data

        #region Public Properties

        public int? Id { get { return ( Record.Id > 0 ) ? (int?)Record.Id : null; } }
        
        internal override string TransactionId
        {
            get
            {
                if ( Id == null )
                {
                    return Table + "_AutoId";
                }

                return Table + "_ManualId";
            }
        }

        public override IEnumerable<SqlParameter> Parameters { get; }

        public int InsertIndex
        {
            // Index from 0, but database starts primary key values from 1
            get { return _insertIndex + 1; }
            set { _insertIndex = value; }
        }

        public Dictionary<Record,Insert> InsertQueries { get; set; }
        
        public string Columns
        {
            get
            {
                List< object > columns = new List< object >();

                if ( Id != null )
                {
                    columns.Add( "id" );
                }

                string foreignKeys = string.Join
                (
                    ", ",
                    Parents.Select
                    (
                        ( parent ) => parent.Metadata.ForeignKey
                    )
                );

                if ( !string.IsNullOrEmpty( foreignKeys ) )
                {
                    columns.Add( foreignKeys );
                }

                string keys = string.Join( ", ", Record.Metadata.Keys );

                if ( !string.IsNullOrEmpty( keys ) )
                {
                    columns.Add( keys );
                }

                return string.Join( ", ", columns );
            }
        }

        public string Values
        {
            get
            {
                List< object > values = new List< object >();

                if ( Id != null )
                {
                    values.Add( Id );
                }

                string foreignKeys = string.Join
                (
                    ", ",
                    Parents.Select
                    (
                        ( parent ) => ( parent.IsNewlyCreated ) ? string.Format( _getOutputIdSqlTemplate, parent.Metadata.Table, InsertQueries[ parent ].InsertIndex ) : $"'{parent.Id}'"
                    )
                );

                if ( !string.IsNullOrEmpty( foreignKeys ) )
                {
                    values.Add( foreignKeys );
                }

                string parameters = string.Join( ", ", Parameters );

                if ( !string.IsNullOrEmpty( parameters ) )
                {
                    values.Add( parameters );
                }

                return string.Format( @"( {0} )", string.Join( ", ", values ) );
            }
        }

        #endregion Public Properties

        #region C-Tor

        public Insert( Record record ) : base( record )
        {
            // ToList() will force immediate evaluation
            Parameters = ( from value in Record.Values select new SqlParameter( $"@insertvar{++ParameterIdPool}", value ?? DBNull.Value ) ).ToList();
        }

        #endregion C-Tor
    }
}
